package org.example.meetingsystem.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.example.meetingsystem.DTO.PaymentDTO;
import org.example.meetingsystem.entity.MeetingRoom;
import org.example.meetingsystem.enums.PaymentStatus;
import org.example.meetingsystem.enums.RoomStatus;
import org.example.meetingsystem.mapper.MeetingRoomMapper;
import org.example.meetingsystem.service.ReservationService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.example.meetingsystem.entity.Reservation;
import org.example.meetingsystem.enums.ReservationStatus;
import org.example.meetingsystem.mapper.ReservationMapper;
import org.example.meetingsystem.service.CancellationService;
import org.example.meetingsystem.util.BusinessException;
import org.example.meetingsystem.DTO.ReservationRequestDTO;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

@Service
@RequiredArgsConstructor
@Slf4j
@Transactional
public class ReservationServiceImpl implements ReservationService {

    private final ReservationMapper reservationMapper;
    private final MeetingRoomMapper meetingRoomMapper;
    private final CancellationService cancellationService;

    @Override
    @Transactional(readOnly = true)
    public List<Reservation> getReservationsByCustomerId(Long customerId) {
        return reservationMapper.selectByCustomerId(customerId);
    }

    @Override
    @Transactional(readOnly = true)
    public List<MeetingRoom> findAvailableRooms(LocalDateTime startTime, LocalDateTime endTime,
                                                Integer attendeeCount, Boolean needProjector,
                                                Boolean needAudio, Boolean needNetwork) {
        log.info("查找可用会议室: startTime={}, endTime={}, attendeeCount={}", startTime, endTime, attendeeCount);

        // 构建查询条件
        QueryWrapper<MeetingRoom> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", RoomStatus.AVAILABLE);

        if (attendeeCount != null) {
            queryWrapper.ge("capacity", attendeeCount);
        }
        if (Boolean.TRUE.equals(needProjector)) {
            queryWrapper.eq("has_projector", true);
        }
        if (Boolean.TRUE.equals(needAudio)) {
            queryWrapper.eq("has_audio", true);
        }
        if (Boolean.TRUE.equals(needNetwork)) {
            queryWrapper.eq("has_network", true);
        }

        List<MeetingRoom> allRooms = meetingRoomMapper.selectList(queryWrapper);

        // 过滤掉在指定时间段内已被预订的会议室
        return allRooms.stream()
                .filter(room -> isRoomAvailable(room.getId(), startTime, endTime))
                .toList();
    }

    private boolean isRoomAvailable(Long roomId, LocalDateTime startTime, LocalDateTime endTime) {
        QueryWrapper<Reservation> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("room_id", roomId)
                .in("status", ReservationStatus.CONFIRMED, ReservationStatus.IN_USE)
                .and(wrapper -> wrapper
                        .between("start_time", startTime, endTime)
                        .or()
                        .between("end_time", startTime, endTime)
                        .or()
                        .and(innerWrapper -> innerWrapper
                                .le("start_time", startTime)
                                .ge("end_time", endTime)));

        return reservationMapper.selectCount(queryWrapper) == 0;
    }

    @Override
    public Reservation createReservation(Long customerId, Long roomId, ReservationRequestDTO requestDTO) {
        log.info("创建预订: customerId={}, roomId={}", customerId, roomId);

        // 验证会议室存在且可用
        MeetingRoom room = meetingRoomMapper.selectById(roomId);
        if (room == null) {
            throw new BusinessException("会议室不存在");
        }
        if (room.getStatus() != RoomStatus.AVAILABLE) {
            throw new BusinessException("会议室不可用");
        }

        // 验证时间有效性
        if (requestDTO.getStartTime().isBefore(LocalDateTime.now()) ||
                requestDTO.getEndTime().isBefore(requestDTO.getStartTime())) {
            throw new BusinessException("预订时间无效");
        }

        // 检查时间段内是否有冲突
        if (!isRoomAvailable(roomId, requestDTO.getStartTime(), requestDTO.getEndTime())) {
            throw new BusinessException("该时间段会议室已被预订");
        }

        // 计算费用
        BigDecimal totalCost = calculateCost(room, requestDTO.getStartTime(), requestDTO.getEndTime());

        // 创建预订
        Reservation reservation = new Reservation();
        reservation.setCustomerId(customerId);
        reservation.setRoomId(roomId);
        reservation.setStartTime(requestDTO.getStartTime());
        reservation.setEndTime(requestDTO.getEndTime());
        reservation.setRequirements(requestDTO.getRequirements());
        reservation.setAttendeeCount(requestDTO.getAttendeeCount());
        reservation.setTotalAmount(totalCost);
        reservation.setStatus(ReservationStatus.LOCKED);
        reservation.setCreatedAt(LocalDateTime.now());

        int result = reservationMapper.insert(reservation);
        if (result <= 0) {
            throw new BusinessException("创建预订失败");
        }

        log.info("预订创建成功: reservationId={}", reservation.getId());
        return reservation;
    }

    private BigDecimal calculateCost(MeetingRoom room, LocalDateTime startTime, LocalDateTime endTime) {
        // 简单的按小时计费逻辑
        long hours = java.time.Duration.between(startTime, endTime).toHours();
        if (hours == 0) hours = 1; // 最少按1小时计费

        return room.getHourlyRate().multiply(BigDecimal.valueOf(hours));
    }

    @Override
    public void payReservation(Long reservationId, PaymentDTO paymentDTO) {
        log.info("处理预订支付: reservationId={}", reservationId);

        Reservation reservation = reservationMapper.selectById(reservationId);
        if (reservation == null) {
            throw new BusinessException("预订不存在");
        }

        if (reservation.getStatus() != ReservationStatus.LOCKED) {
            throw new BusinessException("非锁定状态不允许支付");
        }

        // 检查是否超时（30分钟）
        if (reservation.getCreatedAt().plusMinutes(30).isBefore(LocalDateTime.now())) {
            // 自动取消超时未支付的预订
            reservation.setStatus(ReservationStatus.CANCELLED);
            MeetingRoom meetingRoom = meetingRoomMapper.selectById(reservation.getRoomId());
            meetingRoom.setStatus(RoomStatus.AVAILABLE);
            reservationMapper.updateById(reservation);
            throw new BusinessException("预订已超时，请重新预订");
        }

        // 更新预订状态
        reservation.setTotalAmount(paymentDTO.getAmount());
        reservation.setPaymentStatus(PaymentStatus.PAID);
        reservation.setStatus(ReservationStatus.CONFIRMED);
        reservation.setLockExpiresAt(LocalDateTime.now());

        int result = reservationMapper.updateById(reservation);
        if (result <= 0) {
            throw new BusinessException("更新预订状态失败");
        }

        log.info("预订支付成功: reservationId={}", reservationId);
    }

    @Override
    public void cancelReservation(Long reservationId, Long customerId, String reason) {
        log.info("申请取消预订: reservationId={}, customerId={}", reservationId, customerId);

        Reservation reservation = reservationMapper.selectById(reservationId);
        if (reservation == null) {
            throw new BusinessException("预订不存在");
        }

        if (!reservation.getCustomerId().equals(customerId)) {
            throw new BusinessException("无权操作此预订");
        }

        if (reservation.getStatus() == ReservationStatus.CANCELLED) {
            throw new BusinessException("预订已取消");
        }

        if (reservation.getStatus() == ReservationStatus.COMPLETED) {
            throw new BusinessException("已完成的预订无法取消");
        }

        // 创建取消申请
        cancellationService.createCancellationRequest(reservationId, reason, customerId);

        log.info("取消申请提交成功: reservationId={}", reservationId);
    }

    @Override
    @Transactional(readOnly = true)
    public IPage<Reservation> getReservations(Page<Reservation> page, ReservationStatus status,
                                              Long roomId, Long customerId) {
        QueryWrapper<Reservation> queryWrapper = new QueryWrapper<>();

        if (status != null) {
            queryWrapper.eq("status", status);
        }
        if (roomId != null) {
            queryWrapper.eq("room_id", roomId);
        }
        if (customerId != null) {
            queryWrapper.eq("customer_id", customerId);
        }

        queryWrapper.orderByDesc("created_at");
        return reservationMapper.selectPage(page, queryWrapper);
    }

    @Override
    @Transactional(readOnly = true)
    public List<Reservation> getTodayReservations() {
        return reservationMapper.selectTodayReservations();
    }

    @Override
    public void updateReservationStatus(Long reservationId, ReservationStatus status) {
        Reservation reservation = reservationMapper.selectById(reservationId);
        if (reservation == null) {
            throw new BusinessException("预订不存在");
        }

        reservation.setStatus(status);
        int result = reservationMapper.updateById(reservation);
        if (result <= 0) {
            throw new BusinessException("更新预订状态失败");
        }
    }
}